package cz.apnetis.gwt.client;

import java.util.Date;

import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.HasChangeHandlers;
import com.google.gwt.event.dom.client.HasFocusHandlers;
import com.google.gwt.event.dom.client.HasKeyPressHandlers;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.datepicker.client.DatePicker;

public class DateEditBox extends Composite implements HasValueChangeHandlers<Date>, HasFocusHandlers, HasKeyPressHandlers, HasChangeHandlers, HasValue<Date> {

  /** Panel which contains text box or label */
  private final SimplePanel panel = new SimplePanel();
  /** Base text box to which user can write date */
  private final TextBox textBox = new TextBox();
  /** Label which show value */
  private final Label label = new Label();
  /** Calendar for select date */
  private final DatePicker datePicker = new DatePicker();
  /** Panel on which is date picker show */
  private final PopupPanel calendarPanel = new PopupPanel(false);
  /** Original date value */
  private Date originalValue;

  public DateEditBox() {
    setValue(new Date());

    this.panel.add(this.label);

    this.label.addClickHandler(new ClickHandler() {
      @Override
      public void onClick(final ClickEvent event) {
        DateEditBox.this.panel.clear();
        DateEditBox.this.panel.add(DateEditBox.this.textBox);
        DateEditBox.this.textBox.setFocus(true);
        DateEditBox.this.calendarPanel.setPopupPosition(DateEditBox.this.textBox.getAbsoluteLeft(),
            DateEditBox.this.textBox.getAbsoluteTop() + DateEditBox.this.textBox.getOffsetHeight());
        DateEditBox.this.calendarPanel.show();
      }
    });

    this.calendarPanel.add(this.datePicker);
    this.datePicker.addValueChangeHandler(new ValueChangeHandler<Date>() {
      @Override
      public void onValueChange(final ValueChangeEvent<Date> event) {
        internalChangeValue(event.getValue());
      }
    });

    this.textBox.addValueChangeHandler(new ValueChangeHandler<String>() {
      @Override
      public void onValueChange(final ValueChangeEvent<String> event) {
        internalChangeValue(DateTimeFormat.getShortDateFormat().parse(event.getValue()));
      }
    });
    this.textBox.addKeyPressHandler(new KeyPressHandler() {
      @Override
      public void onKeyPress(final KeyPressEvent event) {
        DateEditBox.this.fireEvent(event);
      }
    });

    initWidget(this.panel);
  }

  private final void internalChangeValue(final Date newValue) {
    this.textBox.setValue(DateTimeFormat.getShortDateFormat().format(newValue));
    this.datePicker.setValue(newValue);
    this.label.setText(this.textBox.getValue());
    this.panel.clear();
    this.panel.add(this.label);
    this.calendarPanel.hide();
    ValueChangeEvent.fireIfNotEqual(this, this.originalValue, newValue);
  }

  @Override
  public final void setValue(final Date newValue) {
    this.originalValue = newValue;
    this.textBox.setValue(DateTimeFormat.getShortDateFormat().format(newValue));
    this.datePicker.setValue(newValue);
    this.label.setText(this.textBox.getValue());
  }

  @Override
  public void setValue(final Date newValue, final boolean fireEvents) {
    setValue(newValue);
    ValueChangeEvent.fire(this, newValue);
  }

  @Override
  public final Date getValue() {
    return this.datePicker.getValue();
  }

  @Override
  public final HandlerRegistration addValueChangeHandler(final ValueChangeHandler<Date> handler) {
    return addHandler(handler, ValueChangeEvent.getType());
  }

  @Override
  public HandlerRegistration addKeyPressHandler(final KeyPressHandler handler) {
    return addHandler(handler, KeyPressEvent.getType());
  }

  @Override
  public HandlerRegistration addFocusHandler(final FocusHandler handler) {
    return addHandler(handler, FocusEvent.getType());
  }

  @Override
  public HandlerRegistration addChangeHandler(final ChangeHandler handler) {
    return addHandler(handler, ChangeEvent.getType());
  }
}
